﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Ionic.Zlib;
using Terraria.Localization;

namespace Terraria.ModLoader.IO
{
	// Token: 0x020002DE RID: 734
	public class TmodFile : IEnumerable<KeyValuePair<string, byte[]>>, IEnumerable
	{
		// Token: 0x170001CE RID: 462
		// (get) Token: 0x06001C30 RID: 7216 RVA: 0x00014280 File Offset: 0x00012480
		// (set) Token: 0x06001C31 RID: 7217 RVA: 0x00014288 File Offset: 0x00012488
		public Version tModLoaderVersion { get; private set; }

		// Token: 0x170001CF RID: 463
		// (get) Token: 0x06001C32 RID: 7218 RVA: 0x00014291 File Offset: 0x00012491
		// (set) Token: 0x06001C33 RID: 7219 RVA: 0x00014299 File Offset: 0x00012499
		public string name { get; internal set; }

		// Token: 0x170001D0 RID: 464
		// (get) Token: 0x06001C34 RID: 7220 RVA: 0x000142A2 File Offset: 0x000124A2
		// (set) Token: 0x06001C35 RID: 7221 RVA: 0x000142AA File Offset: 0x000124AA
		public Version version { get; internal set; }

		// Token: 0x170001D1 RID: 465
		// (get) Token: 0x06001C36 RID: 7222 RVA: 0x000142B3 File Offset: 0x000124B3
		// (set) Token: 0x06001C37 RID: 7223 RVA: 0x000142BB File Offset: 0x000124BB
		public byte[] hash { get; private set; }

		// Token: 0x170001D2 RID: 466
		// (get) Token: 0x06001C38 RID: 7224 RVA: 0x000142C4 File Offset: 0x000124C4
		// (set) Token: 0x06001C39 RID: 7225 RVA: 0x000142CC File Offset: 0x000124CC
		internal byte[] signature { get; private set; } = new byte[256];

		// Token: 0x170001D3 RID: 467
		// (get) Token: 0x06001C3A RID: 7226 RVA: 0x000142D5 File Offset: 0x000124D5
		internal bool ValidModBrowserSignature
		{
			get
			{
				if (this.validModBrowserSignature == null)
				{
					this.validModBrowserSignature = new bool?(ModLoader.IsSignedBy(this, ModLoader.modBrowserPublicKey));
				}
				return this.validModBrowserSignature.Value;
			}
		}

		// Token: 0x06001C3B RID: 7227 RVA: 0x00014305 File Offset: 0x00012505
		internal TmodFile(string path)
		{
			this.path = path;
		}

		// Token: 0x06001C3C RID: 7228 RVA: 0x0001432F File Offset: 0x0001252F
		public bool HasFile(string fileName)
		{
			return this.files.ContainsKey(fileName.Replace('\\', '/'));
		}

		// Token: 0x06001C3D RID: 7229 RVA: 0x004349EC File Offset: 0x00432BEC
		public byte[] GetFile(string fileName)
		{
			byte[] result;
			this.files.TryGetValue(fileName.Replace('\\', '/'), out result);
			return result;
		}

		// Token: 0x06001C3E RID: 7230 RVA: 0x00014346 File Offset: 0x00012546
		internal void AddFile(string fileName, byte[] data)
		{
			this.files[fileName.Replace('\\', '/')] = data;
		}

		// Token: 0x06001C3F RID: 7231 RVA: 0x0001435E File Offset: 0x0001255E
		internal void RemoveFile(string fileName)
		{
			this.files.Remove(fileName.Replace('\\', '/'));
		}

		// Token: 0x06001C40 RID: 7232 RVA: 0x00014376 File Offset: 0x00012576
		public IEnumerator<KeyValuePair<string, byte[]>> GetEnumerator()
		{
			return this.files.GetEnumerator();
		}

		// Token: 0x06001C41 RID: 7233 RVA: 0x00014383 File Offset: 0x00012583
		IEnumerator IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		// Token: 0x170001D4 RID: 468
		// (get) Token: 0x06001C42 RID: 7234 RVA: 0x0001438B File Offset: 0x0001258B
		public int FileCount
		{
			get
			{
				return this.files.Count;
			}
		}

		// Token: 0x06001C43 RID: 7235 RVA: 0x00434A14 File Offset: 0x00432C14
		internal void Save()
		{
			using (MemoryStream memoryStream = new MemoryStream())
			{
				using (DeflateStream deflateStream = new DeflateStream(memoryStream, 0))
				{
					using (BinaryWriter binaryWriter = new BinaryWriter(deflateStream))
					{
						binaryWriter.Write(this.name);
						binaryWriter.Write(this.version.ToString());
						binaryWriter.Write(this.files.Count);
						foreach (KeyValuePair<string, byte[]> keyValuePair in from e in this.files
						orderby TmodFile.GetFileState(e.Key)
						select e)
						{
							binaryWriter.Write(keyValuePair.Key);
							binaryWriter.Write(keyValuePair.Value.Length);
							binaryWriter.Write(keyValuePair.Value);
						}
					}
				}
				byte[] array = memoryStream.ToArray();
				this.hash = SHA1.Create().ComputeHash(array);
				using (FileStream fileStream = File.Create(this.path))
				{
					using (BinaryWriter binaryWriter2 = new BinaryWriter(fileStream))
					{
						binaryWriter2.Write(Encoding.ASCII.GetBytes("TMOD"));
						binaryWriter2.Write(ModLoader.version.ToString());
						binaryWriter2.Write(this.hash);
						binaryWriter2.Write(this.signature);
						binaryWriter2.Write(array.Length);
						binaryWriter2.Write(array);
					}
				}
			}
		}

		// Token: 0x06001C44 RID: 7236 RVA: 0x00434C30 File Offset: 0x00432E30
		internal void Read(TmodFile.LoadedState desiredState, TmodFile.ReadStreamingAsset streamingHandler = null)
		{
			if (desiredState <= this.state)
			{
				return;
			}
			using (FileStream fileStream = File.OpenRead(this.path))
			{
				using (BinaryReader binaryReader = new BinaryReader(fileStream))
				{
					if (Encoding.ASCII.GetString(binaryReader.ReadBytes(4)) != "TMOD")
					{
						throw new Exception("Magic Header != \"TMOD\"");
					}
					this.tModLoaderVersion = new Version(binaryReader.ReadString());
					this.hash = binaryReader.ReadBytes(20);
					this.signature = binaryReader.ReadBytes(256);
					int num = binaryReader.ReadInt32();
					if (this.state < TmodFile.LoadedState.Integrity)
					{
						long position = fileStream.Position;
						byte[] first = SHA1.Create().ComputeHash(fileStream);
						if (!first.SequenceEqual(this.hash))
						{
							throw new Exception(Language.GetTextValue("tModLoader.LoadErrorHashMismatchCorrupted"));
						}
						this.state = TmodFile.LoadedState.Integrity;
						if (desiredState == TmodFile.LoadedState.Integrity)
						{
							return;
						}
						fileStream.Position = position;
					}
					bool flag = this.tModLoaderVersion >= new Version(0, 10, 1, 2);
					using (DeflateStream deflateStream = new DeflateStream(fileStream, 1))
					{
						using (BinaryReader binaryReader2 = new BinaryReader(deflateStream))
						{
							this.name = binaryReader2.ReadString();
							this.version = new Version(binaryReader2.ReadString());
							int num2 = binaryReader2.ReadInt32();
							for (int i = 0; i < num2; i++)
							{
								string text = binaryReader2.ReadString();
								TmodFile.LoadedState fileState = TmodFile.GetFileState(text);
								if (flag && fileState > desiredState)
								{
									break;
								}
								int num3 = binaryReader2.ReadInt32();
								if (fileState == TmodFile.LoadedState.Streaming && desiredState >= TmodFile.LoadedState.Streaming)
								{
									long num4 = deflateStream.TotalOut + (long)num3;
									streamingHandler(text, num3, binaryReader2);
									if (deflateStream.TotalOut < num4)
									{
										binaryReader2.ReadBytes((int)(num4 - deflateStream.TotalOut));
									}
									else if (deflateStream.TotalOut > num4)
									{
										throw new IOException(string.Format("Read too many bytes ({0}>{1}) while loading streaming asset: {2}", deflateStream.Position - num4 - (long)num3, num3, text));
									}
								}
								else
								{
									byte[] data = binaryReader2.ReadBytes(num3);
									if (fileState > this.state && fileState <= desiredState)
									{
										this.AddFile(text, data);
									}
								}
							}
						}
					}
				}
			}
			if (desiredState >= TmodFile.LoadedState.Info && !this.HasFile("Info"))
			{
				throw new Exception("Missing Info file");
			}
			if (desiredState >= TmodFile.LoadedState.Code && !this.HasFile("All.dll") && (!this.HasFile("Windows.dll") || !this.HasFile("Mono.dll")))
			{
				throw new Exception("Missing All.dll or Windows.dll and Mono.dll");
			}
			this.state = desiredState;
			if (this.state > TmodFile.LoadedState.Assets)
			{
				this.state = TmodFile.LoadedState.Assets;
			}
		}

		// Token: 0x06001C45 RID: 7237 RVA: 0x00434F38 File Offset: 0x00433138
		private static TmodFile.LoadedState GetFileState(string fileName)
		{
			if (fileName == "Info" || fileName == "icon.png")
			{
				return TmodFile.LoadedState.Info;
			}
			if (fileName.EndsWith(".dll") || fileName.EndsWith(".pdb"))
			{
				return TmodFile.LoadedState.Code;
			}
			if (fileName.EndsWith(".png") || fileName.EndsWith(".rawimg") || fileName.EndsWith(".mp3") || fileName.EndsWith(".wav") || fileName.EndsWith(".xnb") || fileName.StartsWith("Streaming/"))
			{
				return TmodFile.LoadedState.Streaming;
			}
			return TmodFile.LoadedState.Assets;
		}

		// Token: 0x06001C46 RID: 7238 RVA: 0x00434FD0 File Offset: 0x004331D0
		internal void UnloadAssets()
		{
			this.files = (from file in this.files
			where TmodFile.GetFileState(file.Key) < TmodFile.LoadedState.Assets
			select file).ToDictionary((KeyValuePair<string, byte[]> file) => file.Key, (KeyValuePair<string, byte[]> file) => file.Value);
			this.state = TmodFile.LoadedState.Code;
		}

		// Token: 0x06001C47 RID: 7239 RVA: 0x00435058 File Offset: 0x00433258
		public byte[] GetMainAssembly(bool? windows = null)
		{
			bool valueOrDefault = windows.GetValueOrDefault(ModLoader.windows);
			if (this.HasFile("All.dll"))
			{
				return this.GetFile("All.dll");
			}
			if (!valueOrDefault)
			{
				return this.GetFile("Mono.dll");
			}
			return this.GetFile("Windows.dll");
		}

		// Token: 0x06001C48 RID: 7240 RVA: 0x004350A8 File Offset: 0x004332A8
		public byte[] GetMainPDB(bool? windows = null)
		{
			bool valueOrDefault = windows.GetValueOrDefault(ModLoader.windows);
			if (this.HasFile("All.pdb"))
			{
				return this.GetFile("All.pdb");
			}
			if (!valueOrDefault)
			{
				return this.GetFile("Mono.pdb");
			}
			return this.GetFile("Windows.pdb");
		}

		// Token: 0x040018B1 RID: 6321
		public readonly string path;

		// Token: 0x040018B2 RID: 6322
		private TmodFile.LoadedState state;

		// Token: 0x040018B3 RID: 6323
		private IDictionary<string, byte[]> files = new Dictionary<string, byte[]>();

		// Token: 0x040018B9 RID: 6329
		private bool? validModBrowserSignature;

		// Token: 0x040018BA RID: 6330
		private Exception readException;

		// Token: 0x020002DF RID: 735
		public enum LoadedState
		{
			// Token: 0x040018BC RID: 6332
			None,
			// Token: 0x040018BD RID: 6333
			Integrity,
			// Token: 0x040018BE RID: 6334
			Info,
			// Token: 0x040018BF RID: 6335
			Code,
			// Token: 0x040018C0 RID: 6336
			Assets,
			// Token: 0x040018C1 RID: 6337
			Streaming
		}

		// Token: 0x020002E0 RID: 736
		// (Invoke) Token: 0x06001C4A RID: 7242
		internal delegate void ReadStreamingAsset(string path, int len, BinaryReader reader);
	}
}
